#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sys/time.h>
#include <gmp.h>

gmp_randstate_t state;

double drand();

int main() {

    int i;
    float pontosCirculo = 0, pi = 0;
    long int amostras = 10000000;
    
    double px, py;

    // Declara variaveis para fazer o calculo do speedup do programa.
    struct timeval antes, depois;

    // Pega a hora atual do sistema (desde o Epoch), para saber quando o programa comecou a executar
    gettimeofday(&antes, 0);

    // Declara a variavel para manipular os arquivos que guardarao o valor calculado de PI a cada iteracao
    FILE *arq;

    /* Inicializa semente da função randômica */
    gmp_randinit_default (state);  

    /* Para cada amostra, criar um ponto em (px, py) dentro do quadrado e
       verificar se está dentro do círculo.*/
    
    for(i = 0; i < amostras; i++) {
        px = drand();
        py = drand();
                         
        /* Verificar se a distância do ponto ao centro do círculo
           é menor ou igual a 1. Em caso afirmativo, o ponto pertence 
           ao círculo.*/
        if(sqrt( pow(px - 1, 2) + pow(py - 1, 2) ) <= 1)
            /* Itera pontosCirculo */
            pontosCirculo++;
    }
       
    /* PI = 4 * Área_círculo/Área_quadrado => Área_círculo/Área_quadrado = 
       Pontos_no_círculo/Total_de_pontos. */
    pi = (4*pontosCirculo)/amostras;

    // Abre o arquivo que vai guardar o resultado de PI na iteracao atual
    arq = fopen("MonteCarloSequencial.txt", "w");
    
    if(arq == NULL) {
        printf("Problema ao abrir o arquivo");
        return 1;
    }

    // Imprime o valor calculado de PI no arquivo
    fprintf(arq, "%.30f", pi);

    // Fecha o arquivo desta iteracao
    fclose(arq);

    // Pega a hora atual do sistema (desde o Epoch), para saber quando o programa terminou de executar
    gettimeofday(&depois, 0);

    // Declara a variavel que guardara o valor do speedup do programa
    float speedup;

    // Faz a subtracao entre o horario que o programa terminou e o horario que o programa comecou, para saber quanto tempo ele levou para ser executado
    speedup = (depois.tv_sec + depois.tv_usec/1000000.0) - (antes.tv_sec + antes.tv_usec/1000000.0);
    
    // Abre o arquivo que vai guardar os speedups
    arq = fopen("Speedups.txt", "a+");
    if(arq == NULL){
	printf("Problema ao abrir o arquivo");
    	return 1;
    }

    // Imprime o speedup do programa no arquivo Speedups.txt
    fprintf(arq,"Monte Carlo sequencial: %.10f segundos.\n", speedup);
    
    // Fecha o arquivo de speedup
    fclose(arq);

    return 0;

}

double drand(double a, double b) {

    /* Random integer da GMP */
 
    mpz_t rand_number, rand_max;
    double r;
    
    mpz_init(rand_number);
    mpz_init(rand_max);
    mpz_set_ui(rand_max, 1000000);

    mpz_urandomm(rand_number, state, rand_max);

    r = mpz_get_d(rand_number)/1000000;

    mpz_clear(rand_number);
    mpz_clear(rand_max);
    
    return r*2;
}
